namespace Stee.CAP8.MessageBus.Sagas.Core.Sagas.SagaData
{
    using Stee.CAP8.MessageBus.Sagas.Core.Ioc;
    using System;
    using System.ComponentModel;
    using Microsoft.Extensions.DependencyInjection;
    using System.Runtime.CompilerServices;
    using System.Reflection;
    using System.Threading;
    using System.Collections.Concurrent;
    using Stee.CAP8.MessageBus.Sagas.Core.Sagas.Storages.Steps;
    using Stee.CAP8.MessageBus.Sagas.Core.Sagas.Storages.Dtos.Steps;
    using Stee.CAP8.PropertyChangedNotificator;

    public abstract class BaseSagaData : NotificationObject
    {


        private static readonly ConcurrentDictionary<string, AutoResetEvent> ResetEventSource = new ConcurrentDictionary<string, AutoResetEvent>();
        private AutoResetEvent autoResetEvent;
        private void GetResetEvent() => this.autoResetEvent = ResetEventSource.GetOrAdd(this.SagaId, new AutoResetEvent(true));
        protected BaseSagaData()
        {


        }

        private void BaseSagaData_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.SafeExcute(() =>
            {

                var provider = SagaContainer.ServiceProvider;
                var storage = provider.GetService<ISagaStepStorage>();

                var propertynfo = GetType().GetProperty(e.PropertyName, BindingFlags.Public | BindingFlags.Instance);
                _ = bool.TryParse(propertynfo.GetValue(sender).ToString(), out var proValue);

                storage.Insert(SagaId,
                    new SagaStepDataProperty() { PropertyName = e.PropertyName, PropertyValue = proValue }
                    );
                Console.WriteLine($"存储SagaId={SagaId}-,{e.PropertyName}={proValue}");
            });
        }
        public bool SafeLoadData() => this.SafeExcute(this.LoadData);
        private bool LoadData()
        {
            this.RemovePropertyChangedEventHandler();
            PropertyChanged -= BaseSagaData_PropertyChanged;
            var provider = SagaContainer.ServiceProvider;
            var storage = provider.GetService<ISagaStepStorage>();
            var properties = storage.Find(SagaId);
            Console.WriteLine("========================================================");
            Console.Write($"从数据库加载SagaId={SagaId}");
            properties?.ForEach(property =>
            {

                var propertynfo = this.GetType().GetProperty(property.PropertyName, BindingFlags.Public | BindingFlags.Instance);
                propertynfo.SetValue(this, property.PropertyValue);
                Console.Write($"{property.PropertyName}={property.PropertyValue},");

            });
            Console.WriteLine();
            Console.WriteLine("========================================================");
            this.AddPropertyChangedEventHandler(BaseSagaData_PropertyChanged);
            return true;
        }

        public void SafeExcute(Action action)
        {
            _ = this.autoResetEvent.WaitOne();
            {
                action?.Invoke();
            };
            _ = this.autoResetEvent.Set();

        }
        public T SafeExcute<T>(Func<T> func)
        {
            T result;
            _ = this.autoResetEvent.WaitOne();
            {
                if (func == null)
                {
                    result = default;
                }
                else
                {

                    result = func.Invoke();
                }

            };
            _ = this.autoResetEvent.Set();
            return result;
        }

        private string sagaId { get; set; }
        public string SagaId
        {
            get => this.sagaId;
            set
            {
                this.sagaId = value;

                this.AddPropertyChangedEventHandler(this.BaseSagaData_PropertyChanged);
                this.GetResetEvent();
                _ = this.SafeLoadData();

            }
        }
        public abstract bool IsDone();

    }
}
